import { effect, track, trigger } from "./effect.js";
import { trackTypes, triggerTypes } from "./effectType.js";
import { isFunction } from "./utils.js";
const ISCOMPUTED = Symbol("computed");
export function unifyComputedOpts(opts) {
  if (isFunction(opts)) {
    return {
      get: opts,
      set: (...args) => {
        throw new Error(
          "Warning: No 'setter' configuration was found for the parameters you passed in."
        );
      },
    };
  }

  if (!opts.set) {
    opts.set = (...args) => {
      throw new Error(
        "Warning: No 'setter' configuration was found for the parameters you passed in."
      );
    };
  }

  return opts;
}

export default function computed(getterOrFunciton) {
  const { get, set } = unifyComputedOpts(getterOrFunciton);
  let dirty = false;
  let res;
  let _this;
  let oldValue;
  let newValue;
  // 此处标记的是getter函数，即计算属性所用到的‘依赖项’所运行的effectFn函数
  // effectFn函数每次调用的返回值都是最新值
  const effectFn = effect(get, {
    lazy: true,
    scheduler: () => {
      console.log("computed dependencies effectFn scheduler");
      // 只有当‘依赖项’发生变化时，才会触发此函数
      dirty = false;
      oldValue = newValue;
      newValue = effectFn();
      // 当依赖项发生变化时，手动触发计算属性重新计算，并作派发更新
      trigger(_this, triggerTypes.SET, "value", newValue, oldValue);
    },
  });
  return {
    [ISCOMPUTED]: true,
    get value() {
      _this = this;
      // 这里收集的是'计算属性'的'依赖函数集',而不是‘依赖项’的effectFn
      track(this, trackTypes.GET, "value");
      // console.log("dirty", dirty);
      if (!dirty) {
        dirty = true;
        res = effectFn();
      }
      return res;
    },
    set value(newVal) {
      // console.log("computed set value", deps);
      // 手动触发计算属性所用到的‘依赖项’的变化，间接触发计算属性派发更新（重新计算）
      set(newVal);
    },
  };
}

export function isComputed(val) {
  return !!val[ISCOMPUTED];
}
